# coding:utf-8
from django.db import transaction
from django.db.models import Q, F, Sum
from rest_framework import mixins, viewsets, status

from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.response import Response

from MSB_ERP.utils.base_views import MultipleOpenMixin, MultipleDestroyMixin, MultipleAuditMixin
from MSB_ERP.utils.pagination import GlobalPagination
from financial_info.models import PaymentModel, PaymentItemModel
from rest_framework.decorators import action
from erp_system.models import UserModel
from financial_info.serializer.payment_serializer import PaymentSerializer
from basic_info.models import SupplierModel, SettlementAccountModel
from warehouse_info.models import PurchaseStorageModel


class PaymentViewSet(viewsets.ModelViewSet, MultipleDestroyMixin, MultipleAuditMixin):
    queryset = PaymentModel.objects.all()
    serializer_class = PaymentSerializer
    pagination_class = GlobalPagination

    def get_queryset(self):
        if self.action == 'find':  # 过滤查询
            # 获取请求参数（在json中）
            numbers_code = self.request.data.get('numbers_code', None)
            check_user = self.request.data.get('check_user', 0)
            start_data = self.request.data.get('start_data', None)
            end_data = self.request.data.get('end_data', None)
            supplier = self.request.data.get('supplier', 0)
            operator_user = self.request.data.get('operator_user', 0)
            status = self.request.data.get('status', None)
            account = self.request.data.get('account', None)
            purchase_numbers_code = self.request.data.get('purchase_numbers_code', None)
            query = Q()
            if check_user:
                query.add(Q(check_user__id=check_user), 'AND')
            if numbers_code:
                query.add(Q(numbers_code__contains=numbers_code), 'AND')
            if account:
                query.add(Q(account_id=account), 'AND')
            if start_data:
                query.add(Q(pay_data__gt=start_data), 'AND')
            if end_data:
                query.add(Q(pay_data__lt=end_data), 'AND')
            if supplier:
                query.add(Q(supplier__id=supplier), 'AND')
            if status:
                query.add(Q(status=status), 'AND')
            if operator_user:
                query.add(Q(operator_user__id=operator_user), 'AND')
            if purchase_numbers_code:
                query.add(Q(purchase_numbers_code__contains=purchase_numbers_code), 'AND')
            return PaymentModel.objects.filter(query).distinct().all()
        else:
            return PaymentModel.objects.all()

    params = openapi.Schema(type=openapi.TYPE_OBJECT, properties={
        'check_user': openapi.Schema(type=openapi.TYPE_INTEGER, description="审核人员"),
        'purchase_number_code': openapi.Schema(type=openapi.TYPE_STRING, description="描述订单关键字"),
        'start_date': openapi.Schema(type=openapi.TYPE_STRING, description="起始日期2020-10-01"),
        'number_code': openapi.Schema(type=openapi.TYPE_STRING, description="付款编号(序列号)"),
        'end_date': openapi.Schema(type=openapi.TYPE_STRING, description="结束日期2020-10-01"),
        'status': openapi.Schema(type=openapi.TYPE_STRING, description="状态0或者1"),
        'supplier': openapi.Schema(type=openapi.TYPE_INTEGER, description="供应商的ID"),
        'operator_user': openapi.Schema(type=openapi.TYPE_INTEGER, description="操作用户的ID"),

        'account': openapi.Schema(type=openapi.TYPE_INTEGER, description="结算账户id"),

    })
    # 分页参数必须是query_param(看源码)
    page_param = openapi.Parameter(name='page', in_=openapi.IN_QUERY, description="页号", type=openapi.TYPE_INTEGER)
    size_param = openapi.Parameter(name='size', in_=openapi.IN_QUERY, description="每页显示数量",
                                   type=openapi.TYPE_INTEGER)

    @swagger_auto_schema(method='POST', request_body=params, manual_parameters=[page_param, size_param],
                         operation_description="付款单单的搜索过滤")
    @action(methods=['POST'], detail=False)
    def find(self, request, *args, **kwargs):
        return super(PaymentViewSet, self).list(request=request, *args, **kwargs)

    """
    自定义的批量审核的视图函数
    """

    body_json = openapi.Schema(type=openapi.TYPE_OBJECT, required=['ids'], properties={
        'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER),
                              description="选择需要审核的ID（主键）列表"),
        'user_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='审核用户的ID'),
        # TYPE_ARRAY是列表，items列表里的元素是整数类型
    })  # TYPE_OBJECT传参是json格式,required参数名字,properties规定每个参数的具体类型

    @swagger_auto_schema(method='put', request_body=body_json,
                         operation_description="批量付款")
    @action(methods=['put'], detail=False)
    @transaction.atomic
    def multiple_audit(self, request, *args, **kwargs):
        # 付款单审核
        audit_ids = request.data.get('ids')
        user_id = request.data.get('user_id')  # 用户id
        is_audit = request.data.get('is_audit', '1')  # 反审核
        queryset = self.get_queryset().filter(id__in=audit_ids).all()
        check_user = UserModel.objects.get(id=int(user_id))
        for pm in queryset:  # pm是付款单，付款单审核
            # 判断1：关联的采购单状态是否为’未审核‘
            if pm.purchase and pm.purchase.status == '0':
                return Response(data={'detail': '为审核，不能付款'}, status=status.HTTP_400_BAD_REQUEST)
            # 判断2：付款单的状态是否为”已审核"
            if pm.status == '1':
                return Response(data={'detail': '已审核，不能在审核'}, status=status.HTTP_400_BAD_REQUEST)
            # 判断3：判断结算账户的余额是否够用
            if pm.this_money > pm.account.balance:
                return Response(data={'detail': '余额不够，不能付款'}, status=status.HTTP_400_BAD_REQUEST)

            # 处理关联业务逻辑
            # 业务1：采购定金付款
            if pm.pay_category == '1' and pm.purchase:  # 可以先改状态，再付款，顺序可以改变，在同一个事务里要么一起成功，要么失败
                pm.purchase.status = '5'  # 已付定金
                pm.purchase.save()

            # 业务2：供应商欠款支付
            if pm.pay_category == '3':
                # 修改供应商的欠款
                SupplierModel.objects.filter(id=pm.supplier.id).update(current_pay=F('current_pay') - pm.pay_money)

            # 业务3：入库货款 支付
            if pm.pay_category == '2' and pm.purchase:
                if pm.item_list.exists():  # 这种判断不会从数据库中返回数据
                    for item in pm.item_list.all():  # item是付款项目
                        # 判断4：入库单必须是已经审核状态
                        if item.purchase_storage and item.purchase_storage.status != '1':
                            return Response(data={'detail': '入库单为审核或已经付款'}, status=status.HTTP_400_BAD_REQUEST)
                        # 业务4：第一种情况 对应的入库单是否是：付款完成，首先要查询该入库单的已经付款之和
                        sum_dict = PaymentItemModel.objects.filter(purchase_storage_id=item.purchase_storage.id,
                                                                   payment__status='1') \
                            .aggregate(sum=Sum('this_money'))
                        pay_sum = sum_dict['sum'] if sum_dict['sum'] else 0
                        if item.should_money == (pay_sum + item.this_money):
                            item.purchase_storage.status = '2'  # 把入库单的状态修改为付款完成
                            item.purchase_storage.save()
                        # 业务3：第二种情况，对应的采购单状态是否要改为：采购完成
                        # 采购的完成的条件：1该采购单必须是：全部入库状态 2该采购单中，所有的入库单状态也都是付款完成
                        purchase = item.payment.purchase
                        if purchase.status == '3':
                            # 重新 该采购单中 所有入库单状态不是：‘付款完成’的有多少个
                            number = PurchaseStorageModel.objects.filter(purchase_id=purchase.id).exclude(
                                status='2').count()
                            if number == 0:  # 则所有的入库单状态都为付款完成
                                purchase.status = '4'  # 修改采购单状态为采购完成
                                purchase.save()
                else:
                    return Response(data={'detail': '没有付款项目，支付货款的必须选择'}, status=status.HTTP_400_BAD_REQUEST)
            # 三种业务完成
            #业务四：修改结算账户的余额
            SettlementAccountModel.objects.filter(id=pm.account.id).update(balance=F('balance') - pm.this_money)
            #四种业务都完成，开始修改付款单的状态已经审核信息
            #审核
            self.get_queryset().filter(id__in=audit_ids).update(status='1',check_user_name=check_user.real_name,check_user_id=check_user.id)
            return  Response(status=status.HTTP_200_OK)
